・文字の送受信
C#のコンポーネントの中に.NET Framework 2.0からシリアル通信用のコンポーネントが追加されました。以下にこの通信コンポーネントを使った通信の例を紹介します。
<試作品仕様>
・ PCのCOMポートとPICをつなぎ PC(Microsoft .NET Framework 3.0)とPIC間の通信をおこなう。
送受信は1バイトのASCIIコードとする。(16バイトのUnicodeではない)
・ PCの画面上の”A”、”B”、”C”ボタンをマウスでクリックすると A、B、C が送信される。
・ PIC側でこれを受信し、液晶にそれぞれ以下のように表示する。
(例) 2番目にクリックしたボタンが”B”の場合 …… buf[1]=B
・ ”Enter”ボタンをボタンをクリックすると ”\r”が送信され、それまでに送信されてきた文字すべてをまとめて1行で 液晶に表示する。
(例) ”A” ”B” ”C” とクリックしたあとに”Enter”がクリックされた場合 …… ABC
・また ”Enter”ボタンがクリックされた時にはそれまでに送信されてきた文字をまとめてPC側に送信する。
・PC側ではおくられてきた文字をテキストボックスに表示する
下記については PIC側送受信を参照願います
<試作品回路図><試作品外観><PIC側プログラム><動作結果>
<プログラム> | <動作結果> | |
public byte[] SendData = new byte[10]; string strReceive; public Form1() { InitializeComponent(); serialPort1.PortName = "COM4"; //COM4 ポート使用 serialPort1.BaudRate = 9600; //通信速度 9600bps serialPort1.Parity = System.IO.Ports.Parity.None; //パリティなし serialPort1.DataBits = 8; //データ長 8ビット serialPort1.StopBits = System.IO.Ports.StopBits.One; //ストップビット 1 serialPort1.NewLine = "\r\n";//ReadLine(),WriteLine()が末尾と判断する値の設定 //\r\n:defalut Windows \n: Unix serialPort1.Open(); serialPort1.DtrEnable = true; //DTR(Data Terminal Ready) データ端末レディ serialPort1.RtsEnable = true; //RTS(Request To Send) 送信要求 serialPort1.ReadTimeout = 500; //500mse 読み込みタイムアウト時間 serialPort1.WriteTimeout = 500; //500msec書き込みタイムアウト時間 SendData[0] = (byte)('A'); // または SendData[0] = 0x41; SendData[1] = 0x42; // または SendData[1] = (byte)('B'); SendData[2] = (byte)('C'); // または SendData[2] = 0x43; } private void buttonA_Click(object sender, EventArgs e)//ボタンA { serialPort1.Write(SendData, 0, 1); //COMポートより1バイト送信 オフセット=0 strReceive = serialPort1.ReadLine(); textBox1.Text = strReceive; } private void buttonB_Click(object sender, EventArgs e)//ボタンB { serialPort1.Write(SendData,1, 1); //COMポートより1バイト送信 オフセット=1 strReceive = serialPort1.ReadLine(); textBox1.Text = strReceive; } private void buttonC_Click(object sender, EventArgs e)//ボタンC { serialPort1.Write(SendData, 2, 1); //COMポートより1バイト送信 オフセット=2 strReceive = serialPort1.ReadLine(); textBox1.Text = strReceive; } private void button_Enter_Click(object sender, EventArgs e)//Enterボタン { byte[] EnteData = new byte[10]; EnteData[0] = (byte)('\r'); serialPort1.Write(EnteData, 0, 1); strReceive = serialPort1.ReadLine(); textBox1.Text = strReceive; serialPort1.DiscardInBuffer(); //入力バッファークリア } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { serialPort1.Close(); } |
ボタン”A"を クリックした場合 ボタン”A”、”B”、”C”、 ”C”、”B”、”A”を クリック後”Enter”を クリックした場合 |
<備考>
1. charはC#では2バイトある。 1バイトのASCIIコードで送受信する場合は byteを使用する。
通信の送受信に際してはキャスト(byte)を有効に使用する。
2. C#のデータ型のサイズは以下である。
型の形式 | 型名 | サイズ | 値の範囲 | 備考 |
符号あり 整数 |
sbyte | 8ビット | -128〜127 | sはsignedの略である |
short | 16ビット | -32768〜32767 | ||
int | 32ビット | -2147483648〜2147483647 | ||
long | 64ビット | -9223372036854775808〜9223372036854775807 | ||
符号なし 整数 |
byte | 8ビット | 0〜255 | |
ushort | 16ビット | 0〜65535 | uはunsignedの略である | |
uint | 32ビット | 0〜4294967295 | ||
ulong | 64ビット | 0〜18446744073709551615 | ||
小数点数 | float | 32ビット | 約±1.5×10の-45乗〜±3.4×10の38乗(有効桁7) | |
double | 64ビット | 約±5.0×10の-324乗〜±1.7×10の308乗(有効桁15〜16) | ||
decimal | 128ビット | 約±1.0×10の-28乗〜±7.9×10の28乗(有効桁28〜29) | ||
真理値 | bool | 8ビット | true または flase | |
文字 | char | 16ビット | 0〜65535 |
3. 配列宣言のフォーマットがC#とC,C++では異なる。
C# : char [ ] data = new char [20];
C、C++ : char data[20];
4. SerialPortコンポーネント( →MSDN参照 )
4.1 送信メソッド
publicvoid WriteLine ( string text) ;
publicvoid Write ( string text);
publicvoid Write ( byte [] buffer, uint offset, uint count);
publicvoid Write ( char [] buffer, uint offset, uint count);
パラメータ
text: 出力用の文字列
buffer:ポートに書き込むデータを格納したバイト配列。
offset:書き込みを開始するバッファ配列内のオフセット
count:書き込むバイト数
4.2 受信メソッド
publicstring ReadLine () ;
publicint Read (
byte[] buffer,
int offset,
int count ) ;
publicint Read (
char[] buffer,
int offset,
int count ) ;
パラメータ
buffer:入力の書き込み先となる文字配列。
offset:書き込みを開始するバッファ配列内のオフセット。
count:読み取る文字の数。
■ 文字列の送受信(PC-PIC間) PIC18F4550編
RS232Cによる送受信を理解するには、デリゲート、マルチスレッド、文字コード等に関する若干の知識が必要となります。
以下に例を紹介します。PICと通信を行った例でPIC側はPIC側回路&ソフトを参照願います
<試作品の仕様>
・パソコン側は.NETのC#とし、RS232Cシリアル通信を用いPIC18F4550と文字列の送受信をおこなう。
・PIC側のコンボボックスにあらかじめ下記の文字をセットしておきボタンをクリックすると選択されていた文字列を送信する。
送信される文字の最後尾には’¥r’付加する。
PIC側ではこれらの文字列を受信したら所定の文字列をPC側に返信する。
Oda → Nobunaga
Toyotomi → Hideyoshi
Tokugawa → Ieyasu
Tanaka → Pardon?
・ PIC側では受信文字、送信文字を液晶に表示する。
・ PC側でも受信文字をテキストボックスに表示する。
<プログラム> | ||||
public partial class Form1 : Form { public Form1() { InitializeComponent(); // serialPort1. serialPort1.PortName = "COM4"; //COM4 ポート使用 serialPort1.BaudRate = 9600; //9600bps serialPort1.Parity = System.IO.Ports.Parity.None; //パリティなし serialPort1.DataBits = 8; //データ長 8ビット serialPort1.StopBits = System.IO.Ports.StopBits.One; //ストップビット 1 serialPort1.NewLine = "\r\n";//ReadLine(),WriteLine()が末尾と判断する値の設定 //\r\n:defalut Windows \n: Unix serialPort1.Open(); serialPort1.DtrEnable = true; //DTR(Data Terminal Ready) データ端末レディ serialPort1.RtsEnable = true; //RTS(Request To Send) 送信要求 serialPort1.ReadTimeout = 500; //500mse 読み込みタイムアウト時間 serialPort1.WriteTimeout = 500; //500msec書き込みタイムアウト時間 comboBox1.SelectedIndex = 0; //コンボボックス選択値の初期値設定 } delegate void ReceiveDagete(string str); //string型の引数を持つデリゲートを宣言する。 private void SetText(string str) { ReceiveTextBox.Text = str; } Encoding encSjis = Encoding.GetEncoding("shift-jis"); //シフトJISのエンコードクラスを宣言 Encoding encUni = Encoding.GetEncoding("unicode"); //ユニコード(UCS-16)のエンコードクラスを宣言 private void button1_Click(object sender, EventArgs e) { string strSend = comboBox1.Text; // strSend += '\r'; //終端に\r追加 Byte[] byteArry = encSjis.GetBytes(strSend); //'送信文字をunicode→Shift-jisに変換してをByte配列に格納 serialPort1.Write(byteArry, 0, byteArry.Length); //送信 } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { serialPort1.Close();//シリアルポートクローズ } private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { byte[] byteRead = new byte[serialPort1.BytesToRead]; //バイト単位の配列を生成 serialPort1.Read(byteRead, 0, serialPort1.BytesToRead);//バイト配列を受信 byte[] byteUni = Encoding.Convert(encSjis, encUni, byteRead); //shift-jis からunicodeに変換する string strUni = encUni.GetString(byteUni); //配列をunicodeの文字列に変換 ReceiveDagete receiveDelegete = new ReceiveDagete(SetText); //デリゲートのインスタンス生成 this.Invoke(receiveDelegete, strUni); //セカンドスレッドからメインスレッドのinvoke経由で書き込み } } |
||||
動作結果 | ||||
1台のパソコンのCOM3ポートとCOM4ポート間をクロスケーブル(自作:下記写真参照)で接続した送受信の結果を以下に紹介します。
<試作品の仕様> |
<プログラム> | |
|
|
<実行結果> | |
■ 漢字文字列の送受信(PC−PIC間)
PCとPIC(PIC18F4550)間でのシフトJISによる漢字の送受信の例を紹介します。
<試作品の仕様> → PIC側ソフト、ハード
・パソコン側は.NETのC#とし、RS232Cシリアル通信を用いPIC18F4550と文字列の送受信をおこなう。
・PC側のコンボボックスにあらかじめ下記の文字をセットしておく。送信ボタンをクリックして選択されていた文字列を送信する。
送信される文字の最後尾には’¥r’付加する。
PIC側ではこれらの文字列を受信したら、以下に定めた文字列をPC側に返信する。
織田(織:0x9044 田:0x9363) → 0x904D(信) 0x92B7(長)
豊臣(豊:0x964C 臣:0x9062) → 0x8F47(秀) 0x8B67(吉)
徳川(徳:0x93BF 川:0x90EC) → 0x89C6(家) 0x8D4E(康)
田中 → Pardon?
・ PIC側では受信文字を16進数表示で受信文字 及び送信文字を液晶に表示する。
・ PC側では、受信文字を漢字でテキストボックスに表示する。
<プログラム> | |
public partial class Form1 : Form { //文字を変換するクラスを宣言 Encoding encSjis = Encoding.GetEncoding("shift-jis"); Encoding encUni = Encoding.GetEncoding("unicode"); public Form1() { InitializeComponent(); serialPort1.PortName = "COM4"; //COM4 ポート使用 serialPort1.BaudRate = 9600; //9600bps serialPort1.Parity = System.IO.Ports.Parity.None; //パリティなし serialPort1.DataBits = 8; //データ長 8ビット serialPort1.StopBits = System.IO.Ports.StopBits.One; //ストップビット 1 serialPort1.ReadTimeout = 500; //500mse 読み込みタイムアウト時間 serialPort1.WriteTimeout = 500; //500msec書き込みタイムアウト時間 comboBox1.Items.Clear(); comboBox1.Items.Add("織田"); comboBox1.Items.Add("豊臣"); comboBox1.Items.Add("徳川"); comboBox1.Items.Add("田中"); comboBox1.SelectedIndex = 0; } delegate void ReceiveDelegate(string str);//デリゲート宣言 private void SetText(string str) { textBox1.Text = str; } private void button1_Click(object sender, EventArgs e) { if(serialPort1.IsOpen == false)serialPort1.Open();//シリアルポートオープン string strSend = comboBox1.Text; if (!strSend.EndsWith("\r")) strSend += "\r"; //改行が無かったら \rを追加する Byte[] byteArry = encSjis.GetBytes(strSend); //'送信文字をShift-jisに変換してをByte配列に格納 serialPort1.Write(byteArry, 0, byteArry.Length); //送信 } private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { byte[] byteRead = new byte[serialPort1.BytesToRead]; //受信文字 serialPort1.Read(byteRead, 0, serialPort1.BytesToRead);//読み込み byte[] byteUni = Encoding.Convert(encSjis, encUni, byteRead); //shift-jis からunicodeに変換する string strUni = encUni.GetString(byteUni); //配列を文字列に変換 ReceiveDelegate receiveDelegate = new ReceiveDelegate(SetText); this.Invoke(receiveDelegate, strUni); } } |
<実行結果>
送受信文字 (シフトJIS) |
PC側 | PIC側 (上段:受信データ 下段:送信データ) |
||
織田信長 織:0x9044 田:0x9363 信:0x904D 長:0x92B7 |
||||
豊臣秀吉 豊:0x964C 臣:0x9062 秀:0x8F47 吉:0x8B67 |
||||
徳川家康 徳:0x93BF 川:0x90EC 家:0x89C6 康:0x8D4E |
(注) 液晶表示で1、2バイト目と3、4バイト目の間に1文字分の空白がありますが、これは液晶表示する際漢字(2バイト)データをわかりやすく
するために表示制御で挿入した空白です。実際の送受信においては、4バイトデータの中間に空白データ(0x00など)はありません
PCの全ComPortをコンボボックスに表示してその中の1つをオープンする例を紹介します。 | |
using System; |
<実行結果>
■ PIC32MZ - PC間 シフトJIS漢字 文字列送受信
★ PICとPC(VC#)間のUARTによる、シフトJIS漢字文字列送受信の例を紹介します。
VC# 2022のプロジェクトファイル、実行ファイルは、以下からダウンロードできます。
(VC# 2022 プロジェクトファイル、 同実行ファイル)
★ (PC側のアプリケーションについは( →URL ) 参照願います。
<仕様>
・PCとPIC32MZ間でUART接続による文字列の送受信をおこなう。
・漢字の文字コードはシフトJISを使うこと。
・PC側から文字列に対して PIC側からそれぞれに対応した文字列を返信すること
送受信の文字列は 以下とする
PCからの送信文字列 | PICからの返信文字列 | |
織田 | 信長 | |
豊臣 | 秀吉 | |
徳川 | 家康 | |
Oda | Nobunaga(信長) | |
Toyotomi | Hideyoshi(秀吉) | |
Tokugawa | Ieyasu(家康) | |
How are you ? | Pardon ? | |
ご機嫌いがかですか ? | Pardon ? |
・PICは起動後すみやかに PC側に 下記文字列を送信のこと
"UART 接続完了 !"
・PC側のアプリケーションは マイクロソフトのVC# で作成のこと。
・PC側のアプリケーションは以下のようなダイアログウィンドウとする。
すなわち、
1. コンボボックスから送信文字列を選択して 送信ボタンをクリックするとPIC側に送信をおこなう。
2. 受信文字列は リッチテキストボックスに順次追加表示する。
<動作結果> (→ 動画: 1080pのHD動画を見ることができます。)
1. PIC起動後、"UART 接続完了 !"を 受信した時 | |
2. "織田" を送信後、"信長"を受信した時 | |
3. "Oda" を送信後、"Nobunaga(信長)を受信した時 | |
4. "ご機嫌いかがですか ?" を送信後、 "Pardon"を受信した時 | |
Form1.cs[デザイン] | |
Form1.cs | |
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.IO.Ports; //追加 シリアルポートコンポーネント用 using static System.Windows.Forms.VisualStyles.VisualStyleElement; namespace _011_PC_PIC_UART_S_JIS_Nobunaga { public partial class Form1 : Form { //文字を変換するクラスを宣言 Encoding encSjis = Encoding.GetEncoding("shift-jis"); Encoding encUni = Encoding.GetEncoding("unicode"); delegate void ReceiveDelegate(string str);//デリゲート宣言 public Form1() { InitializeComponent(); SendDataCBox.Items.Clear(); SendDataCBox.Items.Add("織田"); SendDataCBox.Items.Add("豊臣"); SendDataCBox.Items.Add("徳川"); SendDataCBox.Items.Add("Oda"); SendDataCBox.Items.Add("Toyotomi"); SendDataCBox.Items.Add("Tokugawa"); SendDataCBox.Items.Add("How are you ?"); SendDataCBox.Items.Add("ご機嫌いかがですか?"); SendDataCBox.SelectedIndex = 0; string[] PortList = SerialPort.GetPortNames(); try { ComCBox.Items.Clear(); //シリアルポート名をコンボボックスにセット foreach (string PortName in PortList) { ComCBox.Items.Add(PortName); } if (ComCBox.Items.Count > 0) { ComCBox.SelectedIndex = 0; } serialPort1.PortName = ComCBox.SelectedItem.ToString(); // serialPort1.PortName = "COM3"; //COM1 ポート使用 // serialPort1.PortName = "COM4"; //COM1 ポート使用 serialPort1.BaudRate = 115200; //9600bps //serialPort1.BaudRate = 9600; //9600bps serialPort1.Parity = System.IO.Ports.Parity.None; //パリティなし serialPort1.DataBits = 8; //データ長 8ビット serialPort1.StopBits = System.IO.Ports.StopBits.One; //ストップビット 1 serialPort1.ReadTimeout = 500; //500mse 読み込みタイムアウト時間 serialPort1.WriteTimeout = 500; //500msec書き込みタイムアウト時間 serialPort1.Open();//シリアルポートオープン } catch (Exception ex) { DialogResult result = MessageBox.Show (ex.Message + "\n" + "COMポートがひらけません。COMポートを接続してから本アプリケーションを起動してください。"); } } private void SendBtn_Click(object sender, EventArgs e) { serialPort1.DiscardInBuffer(); //受信バッファのデータクリア // serialPort1.DiscardOutBuffer(); //送信バッファのデータクリア string strSend = SendDataCBox.Text; if (!strSend.EndsWith("\r")) strSend += "\r"; //改行が無かったら \rを追加する Byte[] byteArry = encSjis.GetBytes(strSend); //'送信文字をShift-jisに変換してをByte配列に格納 serialPort1.Write(byteArry, 0, byteArry.Length); //送信 } private void ClearBtn_Click(object sender, EventArgs e) { richTextBox1.Clear(); } private void SetText(string str) { richTextBox1.Focus(); //最終行にフォーカスをセット richTextBox1.AppendText(str); //文字列追加 } private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) { byte[] byteRead = new byte[serialPort1.BytesToRead]; //受信文字 serialPort1.Read(byteRead, 0, serialPort1.BytesToRead);//読み込み byte[] byteUni = Encoding.Convert(encSjis, encUni, byteRead); //shift-jis からunicodeに変換する string strUni = encUni.GetString(byteUni); //配列を文字列に変換 ReceiveDelegate receiveDelegate = new ReceiveDelegate(SetText); this.Invoke(receiveDelegate, strUni); } private void ComCBox_TextChanged(object sender, EventArgs e) { if (serialPort1.IsOpen == true) { serialPort1.Close();//シリアルポートクローズ serialPort1.PortName = ComCBox.SelectedItem.ToString(); serialPort1.BaudRate = 115200; //115200bps //serialPort1.BaudRate = 9600; //9600bps serialPort1.Parity = System.IO.Ports.Parity.None; //パリティなし serialPort1.DataBits = 8; //データ長 8ビット serialPort1.StopBits = System.IO.Ports.StopBits.One; //ストップビット 1 serialPort1.ReadTimeout = 500; //500mse 読み込みタイムアウト時間 serialPort1.WriteTimeout = 500; //500msec書き込みタイムアウト時間 serialPort1.Open();//シリアルポートオープン } } } } |